package database;

/*
 * @Author James Metting
 */

import javax.media.opengl.*;

import com.sun.opengl.util.*;
import com.sun.opengl.util.j2d.TextRenderer;

import java.applet.*;
import java.awt.*;

import javax.media.opengl.GL;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLAutoDrawable;
import java.awt.event.*;


public class PuzzleApplet extends Applet implements GLEventListener, KeyListener, MouseListener
{
	static GLCanvas canvas;
	PuzzleColor backColor;
	PuzzlePiece[] pieces;
	int pieceSize;
	static boolean hasSelection;
	PuzzlePiece selected;
	float index = 0;
	FPSAnimator animator;
	TextRenderer[] renderer;
	Color textColor = new Color(0,0,0);;
	int[] order;// tells the order in which the pieces should be displayed
	int coolColor;
    LoadFile fileLoader;
    String[] load = {"LOAD"};

	public void init()
     {
		coolColor =0;

    	 canvas = new GLCanvas();
         this.add(canvas);
         int canvasWidth = 700;
   		int canvasHeight = 700;
   		Dimension dimension = new Dimension(canvasWidth, canvasHeight);
   		canvas.setSize(dimension);
   		this.setSize(dimension);
   		canvas.addGLEventListener(this);
   	    canvas.addKeyListener(this);
   	    canvas.addMouseListener(this);
   	    animator = new FPSAnimator(canvas, 50); // set animator and frame rate
   	    fileLoader = new LoadFile();
     }
     //important for calculating piece positions
     public static int getYval()
     {
    	 return canvas.getHeight();
     }
     public static int getXval()
     {
    	 return canvas.getWidth();
     }
     /**
      * Starts the applet and sets up the puzzle or resets the puzzle
      * may be useful as a button call later
      */
     public void start()
     {
    	 backColor = new PuzzleColor(1,1,1);
    	 pieces = new PuzzlePiece[1];
    	 pieces =PuzzleCreator.sample();
    	 order = new int[pieces.length];
    	 for (int i = 0;i<order.length;i++)
    	 {
    		 order[i]=i;//initializes the order to be same as index
    	 }
    	 renderer = new TextRenderer[4];


    	 animator.start();//important for animating


     }
     public void stop()
     {
     }


     public void paint(Graphics g)
     {

     }
     //GLEventListener methods
     //important for GL
     public void init(GLAutoDrawable drawable)
     {

     }
     public void displayChanged(GLAutoDrawable drawable,boolean bool1,boolean bool2)
     {}
     public void display(GLAutoDrawable drawable)
     {
    	GL gl = drawable.getGL();
     	gl.glClearColor(0, 0, 0, 1);
        gl.glClear(GL.GL_COLOR_BUFFER_BIT);
        gl.glColor3d(1, 1, 1);
    	gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();


        if (renderer[0] ==null)
        {

        	Font font;
            Color color;
            font = new Font("Comic Sans MS",Font.PLAIN,50);

        	renderer[0] = new TextRenderer(font);
        	renderer[0].setColor(textColor);

        	font = new Font("ArialBlack",Font.BOLD,100);
        	renderer[1] = new TextRenderer(font);
        	renderer[1].setColor(textColor);

        	font = new Font("Arial",Font.BOLD,75);
        	renderer[2] = new TextRenderer(font);
        	renderer[2].setColor(textColor);

        	font = new Font("Times New Roman",Font.PLAIN,60);
        	renderer[3] = new TextRenderer(font);
        	renderer[3].setColor(textColor);
        }

        if(backColor!=null)
        	displayBackground(drawable);
		//updates the piece thats moving for visual asthetics
        try{
		if(hasSelection)
   	 	{
   	 		 Point posit = canvas.getMousePosition();
  	     	 selected.setLocation((int)posit.getX(),(int)posit.getY());
   	 	}
        }catch(NullPointerException ne)
        {
        	//System.out.println("OFF SCREEN");
        }
        if(selected!=null)
   	 {
   		 selected.updateAttached();
   	 }
        if(pieces!=null)//startup null pointer issue (should be fixed now)
        {
	    	 for (int i = (pieces.length-1); i>=0; i--)
	    	 {
	    		 pieces[order[i]].display(drawable, backColor);
	    		 pieces[order[i]].setUpdated(false);
	    		 emitString(drawable,pieces[order[i]].text,
	    				 (float)(pieces[order[i]].location.x+.02),
	    				 (float)(pieces[order[i]].location.y+PuzzlePiece.size-.02),
	    				 pieces[order[i]].getLevel());
	    	 }
        }
        //Load Button

        emitString(drawable,load,.75f,-.9f,1);
     }
     /**
      * displays the background as a square of a given color
      * @param drawable
      * @param backColor
      */
     public void displayBackground(GLAutoDrawable drawable)
 	{
 		GL gl = drawable.getGL();
 		gl.glPushMatrix();
 		gl.glColor3f(backColor.getRed(), backColor.getGreen(), backColor.getBlue());

 		//SQUARE -draws the base square in the above color
 		gl.glBegin( GL.GL_QUADS );
 		gl.glVertex3f( -1,1, 1 );
 		gl.glVertex3f( 1,1, 1 );
 		gl.glVertex3f(1,-1, 1 );
 		gl.glVertex3f( -1,-1,1 );
 		//display text
 		gl.glMatrixMode(GL.GL_MODELVIEW);
 		//emitString(drawable,text, (float)(location.x+size-.05), (float)(location.y+.05));
 		//PuzzleApplet.emitString(drawable,text, (float)(location.x+size-.05), (float)(location.y+.05));
 		gl.glEnd();
 		gl.glPopMatrix();
 	}
     /**
      * reShape initializes all of the core components for displaying
      * images on the Canvas.
      */
     public void reshape(GLAutoDrawable drawable, int x, int y, int w,
             int h)
         {
	    	 GL gl = drawable.getGL();
	         gl.glViewport(x, y, w, h);
	         canvas.requestFocusInWindow();
         }
     /** Key processing callback method */
     public void keyPressed(KeyEvent e) {
         if ( e.getKeyCode() == KeyEvent.VK_ESCAPE ) {
             System.exit(0);
         }
         else if(e.getKeyCode()==KeyEvent.VK_L)
    	 {
    		 PuzzlePiece[] piecesTemp=fileLoader.load();
    		 if (piecesTemp!=null)
    		 {
    			 pieces = piecesTemp;
    		 }
    		 order = new int[pieces.length];
        	 for (int i = 0;i<order.length;i++)
        	 {
        		 order[i]=i;//initializes the order to be same as index
        	 }

    	 }
         else {
             System.out.println("Not processed key");
         }
         canvas.repaint();
     }

     /** Not used method, but needed to instanciate KeyListener */
     public void keyReleased(KeyEvent e)
     {
     }

     /** Not used method, but needed to instanciate KeyListener */
     public void keyTyped(KeyEvent e)
     {

     }
     //Invoked when the mouse button has been clicked (pressed and released) on a component.
     public void 	mouseClicked(MouseEvent e)
     {
    	 //load button
    	 if(e.getX()>615&&e.getX()<692&&e.getY()>668&&e.getY()<690)
 		 {
    		 PuzzlePiece[] piecesTemp=fileLoader.load();
    		 if (piecesTemp!=null)
    		 {
    			 pieces = piecesTemp;
    		 }
    		 order = new int[pieces.length];
        	 for (int i = 0;i<order.length;i++)
        	 {
        		 order[i]=i;//initializes the order to be same as index
        	 }
 		 }
    	 hasSelection = false;
    	 for (int i = (pieces.length-1); i>=0; i--)
    	 {
    		 pieces[order[i]].setUpdated(false);
    	 }
    	 PuzzlePiece sel = null;
    	 boolean hassel = false;
			for (int i = 0; i<pieces.length &&!hassel;i++)
			{
				if(pieces[order[i]].isMovable(e.getX(), e.getY()))
				{
					sel = pieces[order[i]];
					hassel = true;
					swapOrder(i);
				}
			}
    	 if(e.getButton()==MouseEvent.BUTTON1)
    	 {
    		 if(sel!=null)
    			 sel.rotateCounter();

    	 }
    	 else if(e.getButton()==MouseEvent.BUTTON3)
    	 {
    		 if(sel!=null)
    			 sel.rotateClock();
    	 }
     }
     //   Invoked when the mouse enters a component.
	public void 	mouseEntered(MouseEvent e)
	{
	}
	//	Invoked when the mouse exits a component.
	public void 	mouseExited(MouseEvent e)
	{
	}
	//	Invoked when a mouse button has been pressed on a component.
	public void 	mousePressed(MouseEvent e)
	{
		hasSelection = false;
		for (int i = 0; i<pieces.length &&!hasSelection;i++)
		{
			if(pieces[order[i]].isMovable(e.getX(), e.getY()))
			{
				selected = pieces[order[i]];
				hasSelection = true;
				swapOrder(i);
			}
		}

	}
//	Invoked when a mouse button has been pressed on a component.
	//check proximity of two pieces HERE!!!!
	public void 	mouseReleased(MouseEvent e)
	{
		//System.out.println("RELEASED"+e.getX()+e.getY());
		if(hasSelection)
		{
			selected.setLocation(e.getX(),e.getY());
			selected.checkNeighbor();
			hasSelection=false;
		}
	}
	/**
     * String creation class, outputs a String onto the
     * board in the specified position
     * tx,ty positions
     * @param s
     * @param tx
     * @param ty
     */
	private void emitString(GLAutoDrawable drawable, String[] text, float tx, float ty,int textLevel)
	{
		double distance=.1;
		switch (textLevel)
		{
		case 1:distance = .065;break;
		case 2:distance = .048;break;
		case 3:distance = .03;break;
		}
        renderer[textLevel].begin3DRendering();
        	for (int i = 0; i<text.length;i++)
     	   {
        		ty -= distance;
        		renderer[textLevel].draw3D(text[i],tx,ty,-1,.0008f);
     	   }
        renderer[textLevel].end3DRendering();

	}
	/**
	 * puts index in the front of the order and moves everything up one
	 * @param index
	 */
	private void swapOrder(int index)
	{
		int temp = order[index];//holds value for the front
		for (int i = index; i >=1;i--)
		{
			order[i] = order[i-1];
		}
		order[0] =temp;
	}

}